﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Web.UI.WebControls;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
using Lswweb.Model;
using Lswweb.IDAL;

namespace Lswweb.Domain
{
    public class TreeTables
    {
        #region 成员变量及构造方法

        private ITreeTable<CategoryInfo> treeTableDAL;
        private TreeTableType treeType;

        private TreeTables(TreeTableType treeTableType)
        {
            this.treeType = treeTableType;
            treeTableDAL = DALFactory.CreateTreeTableDAL(treeType);
        }

        /// <summary>
        /// 文章表
        /// </summary>
        private static TreeTables newsCategories;
        public static TreeTables NewsCategories
        {
            get
            {
                if (newsCategories==null)
                    newsCategories = new TreeTables(TreeTableType.NewsCategories);

                return newsCategories;
            }
        }

        /// <summary>
        /// 产品表
        /// </summary>
        private static TreeTables productCategories;
        public static TreeTables ProductCategories
        {
            get
            {
                if (productCategories == null)
                    productCategories = new TreeTables(TreeTableType.ProductCategories);

                return productCategories;
            }
        }

        /// <summary>
        /// linkcategories
        /// </summary>
        private static TreeTables linkCategories;
        public static TreeTables LinkCategories
        {
            get
            {
                if (linkCategories == null)
                    linkCategories = new TreeTables(TreeTableType.LinkCategories);

                return linkCategories;
            }
        }

        /// <summary>
        /// UpFileCategories
        /// </summary>
        private static TreeTables upFileCategories;
        public static TreeTables UpFileCategories
        {
            get
            {
                if (upFileCategories == null)
                    upFileCategories = new TreeTables(TreeTableType.UpFileCategories);

                return upFileCategories;
            }
        }

        private static TreeTables cities;
        public static TreeTables Cities
        {
            get
            {
                if(TreeTables.cities==null)
                    TreeTables.cities=new TreeTables(TreeTableType.Cities);

                return TreeTables.cities;
            }
        }

        private static TreeTables brand;
        public static TreeTables Brand
        {
            get
            {
                if (TreeTables.brand == null)
                    TreeTables.brand = new TreeTables(TreeTableType.Brand);

                return TreeTables.brand;
            }
        }
        
        /// <summary>
        /// 根据类型自动选择树形表
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static TreeTables TreeTable(TreeTableType type)
        {
            switch (type)
            {
                case TreeTableType.NewsCategories:
                    return TreeTables.NewsCategories;
                case TreeTableType.ProductCategories:
                    return TreeTables.ProductCategories;
                case TreeTableType.LinkCategories:
                    return TreeTables.LinkCategories;
                case TreeTableType.UpFileCategories:
                    return TreeTables.UpFileCategories;
                case TreeTableType.Cities:
                    return TreeTables.Cities;
                case TreeTableType.Brand:
                    return TreeTables.Brand;
                default:
                    throw new Exception("未设置type属性。");
            }
        }

        #endregion

        #region 公共方法
        /// <summary>
        /// 根据标示Id取得实体类
        /// </summary>
        /// <param name="id">标示Id</param>
        /// <returns>类体类</returns>
        public CategoryInfo GetModelById(int id)
        {
            if (id <= 0)
                return null;

            return GetCacheModel(id);
        }

        public CategoryInfo GetBaseNode(int categoryId)
        {
            if (categoryId <= 0)
                return null;

            CategoryInfo info = GetCacheModel(categoryId);
            if (info == null)
                return null;

            int baseNodeId = Convert.ToInt32(info.Path.Split('/')[0]);
            return GetCacheModel(baseNodeId);
        }

        /// <summary>
        /// 根据父节点标示Id取得同级节点实体记录集合
        /// </summary>
        /// <param name="parentId">父节点标示Id</param>
        /// <returns>实体记录集合</returns>
        public IList<CategoryInfo> GetModelsByParentId(int parentId)
        {
            return GetModelsByParentId(parentId, true);
        }
        public IList<CategoryInfo> GetModelsByParentId(int parentId, bool isOnlyEnable)
        {
            int total;
            return GetModelsByParentId(parentId, isOnlyEnable, 999, 1, out total);
        }
        public IList<CategoryInfo> GetModelsByParentId(int parentId, bool isOnlyEnable,int pageSize, int pageIndex, out int total)
        {
            if (pageIndex <= 0)
                pageIndex = 1;

            IEnumerable<CategoryInfo> list=Items;
            if (parentId >= 0)
                list = list.Where(info => info.ParentId == parentId);
    
            if (isOnlyEnable)
                list = list.Where(info => info.Status);

            total = list.Count();

            int beginIndex = (pageIndex - 1) * pageSize;
            return list.OrderBy(info => info.DisplayOrder).Skip(beginIndex).Take(pageSize).ToList();
        }

        public IList<CategoryInfo> GetModels()
        {
            return Items;
        }

        public IList<CategoryInfo> GetModelsByDepth(int depth, params int[] baseParentId)
        {
            if (depth <= 0 && (baseParentId == null || baseParentId.Length==0))
                depth = 1;

            IEnumerable<CategoryInfo> list = Items.OrderBy(info => info.Id).Where(info=>info.Status==true);
            if (depth > 0)
                list = list.Where(info => info.Depth == depth);

            if (baseParentId != null && baseParentId.Length>0)
            {
                if (depth > 0)
                    list = list.Where(info=> baseParentId.Count(id => IsChildNode(id,info.Id))>0);
                else
                    list = list.Where(info => baseParentId.Contains(info.ParentId));
            }


                return list.ToList<CategoryInfo>();
        }

        /// <summary>
        /// 根据实体类添加一条记录
        /// </summary>
        /// <param name="modelInfo">类体类</param>
        /// <returns>新记录标示Id</returns>
        public int InsertByModel(CategoryInfo modelInfo)
        {
            int id=treeTableDAL.Insert(modelInfo);
            UpdateCache(id);
            return id;
        }

        /// <summary>
        /// 根据实体类更新一条记录
        /// </summary>
        /// <param name="modelInfo">实体类</param>
        /// <returns>是否更新成功</returns>
        public void UpdateByModel(CategoryInfo modelInfo)
        {
            bool label= treeTableDAL.Update(modelInfo);
            UpdateCache(modelInfo.Id);
        }

        public void UpdateIcon(int id, string url)
        {
            CategoryInfo info = GetModelById(id);
            if (info == null)
            {
                SiteContext.RenderMessage(ExceptionType.PageNotFond);
            }
            else
            {
                DeleteIcon(info);

                url=ImageHelper.MoveImagesToDirectory(SiteModule.TreeView, url);
                if(treeTableDAL.UpdateField(info.Id,"Icon",url))
                    SiteContext.RenderMessage(ExceptionType.HandleSuccess);
                else
                    SiteContext.RenderMessage(ExceptionType.UnknownError);

                UpdateCache(info.Id);
            }
        }
        private void DeleteIcon(CategoryInfo info)
        {
            if (info == null)
                return;

            if (!string.IsNullOrEmpty(info.Icon))
                Globals.FileDelete(info.Icon);
        }

        /// <summary>
        /// 根据两记录的标示Id交换两条记录的DisplayOrder字段值
        /// </summary>
        /// <returns>是否更新成功</returns>
        public void UpdateChangeDisplayOrderById(int id, int id2)
        {
            bool label = treeTableDAL.ExchangeDisplayOrder(id, id2);
            CategoryInfo cacheInfo = GetCacheModel(id);
            CategoryInfo cacheInfo2 = GetCacheModel(id2);
            int displayOrder = cacheInfo.DisplayOrder;
            cacheInfo.DisplayOrder = cacheInfo2.DisplayOrder;
            cacheInfo2.DisplayOrder = displayOrder;
        }

        /// <summary>
        /// 根据标示Id更新记录的父标示Id
        /// </summary>
        /// <param name="id">标示Id</param>
        /// <param name="newParentId">新的父Id指向</param>
        /// <returns>是否更新成功</returns>
        public void UpdateParentIdById(int id, int newParentId)
        {
            treeTableDAL.UpdateParentId(id, newParentId);
            ClearCache();
        }

        /// <summary>
        /// 根据标示Id更新记录的排序字段DisplayOrder
        /// </summary>
        /// <param name="id">标示Id</param>
        /// <param name="newDisplayOrder">新的排序位置</param>
        /// <returns>是否更新成功</returns>
        public void UpdateDisplayOrderById(int id, int newDisplayOrder)
        {
            treeTableDAL.UpdateDisplayOrder(id, newDisplayOrder);
            ClearCache();
        }

        /// <summary>
        /// 根据标示Id删除一条记录
        /// </summary>
        /// <param name="id">标示Id</param>
        /// <returns>是否删除</returns>
        public void DeleteById(int id)
        {
            CategoryInfo info = GetModelById(id);
            if (info == null)
                SiteContext.RenderMessage(ExceptionType.UnknownError);

            DeleteIcon(info);

            bool label = treeTableDAL.Delete(id);

            DeleteCache(id);
        }

        public string GetPath(int id)
        {
            CategoryInfo cacheInfo = GetCacheModel(id);
            if (cacheInfo != null)
                return cacheInfo.Path;
            else
                return string.Empty;
        }

        public string GetPathText(int id)
        {
            return GetPathText(id," > ",0);
        }
        public string GetPathText(int id,int depth)
        {
            return GetPathText(id, " > ",depth);
        }
        public string GetPathText(int id,string split,int depth)
        {
            string str = string.Empty;
            string path = GetPath(id);

            if (string.IsNullOrEmpty(path))
                return str;
            
            Regex regex = new Regex("^(" + path.Replace("/", "|") + ")$");
            IList<CategoryInfo> list = Items.Where(node => regex.IsMatch(node.Id.ToString()) && (depth<=0 || depth<=node.Depth)).OrderBy(node => node.Id).ToList();
            foreach (CategoryInfo node in list)
                str += node.Title + split;

            return str.TrimEnd(split.ToCharArray());
        }

        /// <summary>
        /// 取得第一个子类的Id,如果不存在子类则返回自身
        /// </summary>
        /// <param name="id">类别Id</param>
        /// <returns></returns>
        public CategoryInfo GetFirstChildNode(int id)
        {
            return Items.OrderBy(info=>info.DisplayOrder).FirstOrDefault(info => info.ParentId == id);
        }

        public CategoryInfo GetLastChildNode(int id)
        {
            return Items.OrderBy(info => info.DisplayOrder).LastOrDefault(info=> info.ParentId==id);
        }

        /// <summary>
        /// 判断childId节点是否属于id的下级级联节点
        /// </summary>
        public bool IsChildNode(int id,int childId)
        {
            CategoryInfo categoryInfo = GetCacheModel(childId);
            return categoryInfo.Path.Split('/').Contains(id.ToString());
        }

        public string GetCategoryName()
        {
            int categoryId = SiteContext.Current.CategoryId;
            if (categoryId <= 0)
                return string.Empty;
            else
                return GetCategoryName(categoryId);
        }
        public string GetCategoryName(int categoryId)
        {
            if (categoryId <= 0)
                return string.Empty;

            CategoryInfo categoryInfo = GetCacheModel(categoryId);
            if (categoryInfo != null)
                return categoryInfo.Title;
            else
                return string.Empty;
        }

        #endregion

        #region UI

        public void BinderToListControl(ListControl listControl, IList<CategoryInfo> dataSource)
        {
            if (dataSource == null || listControl==null)
                return;

            listControl.DataSource = dataSource;
            listControl.DataTextField = "Title";
            listControl.DataValueField = "Id";
            listControl.DataBind();
        }

        public void BinderToListControl(ListControl listControl,int parentId)
        {
           BinderToListControl(listControl,GetModelsByParentId(parentId,true));
        }

        public void BinderToListControl(ListControl listControl, int depth,params int[] baseParentId)
        {
            BinderToListControl(listControl, GetModelsByDepth(depth, baseParentId));
        }

        #region Binder To TreeView
 
        public void BinderTreeView(TreeView treeView, bool IsRelating, int parentId, bool showParentNode)
        {
            treeView.Nodes.Clear();
            TreeNodeCollection treeNodeCollection = treeView.Nodes;
            if (showParentNode && parentId > 0)
            {
                CategoryInfo categoryInfo = GetModelById(parentId);
                if (categoryInfo != null)
                {
                    TreeNode node = new TreeNode();
                    node.Value = categoryInfo.Id.ToString();
                    node.Text = categoryInfo.Title;
                    treeView.Nodes.Add(node);

                    treeNodeCollection = node.ChildNodes;
                }
            }

            IList<CategoryInfo> list =  GetModelsByParentId(parentId,false);
            BinderTreeNode(list, treeNodeCollection);
            BinderChildNodes(treeView, treeNodeCollection, IsRelating);
        }

        private void BinderChildNodes(TreeView treeView, TreeNodeCollection treeNodes, bool IsRelating)
        {
            for (int i = 0; i < treeNodes.Count; i++)
            {
                TreeNode childTreeNode = treeNodes[i];
                childTreeNode.ChildNodes.Clear();
                int parentId = Convert.ToInt32(childTreeNode.Value);
                IList<CategoryInfo> childList =  GetModelsByParentId(parentId, false);
                BinderTreeNode(childList, childTreeNode.ChildNodes);

                if (IsRelating)
                    BinderChildNodes(treeView, childTreeNode.ChildNodes, IsRelating);
            }
        }


        /// <summary>
        /// 绑定树形控件
        /// </summary>
        /// <param name="list">要绑写到树形目录的实体类集合</param>
        /// <param name="parentNode">实体类要绑定到的TreeNode</param>
        private void BinderTreeNode(IList<CategoryInfo> list, TreeNodeCollection parentNode)
        {
            if (list == null || list.Count == 0)
                return;

            foreach (CategoryInfo model in list)
            {
                TreeNode node = new TreeNode();
                node.Value = model.Id.ToString();
                node.Text = model.Title;
                parentNode.Add(node);
            }
        }

        #endregion

        #endregion

        #region Cache

        private IList<CategoryInfo> Items
        {
            get
            {
                IList < CategoryInfo > items = Globals.GetCacheManage[CacheKey] as IList<CategoryInfo>;
                if (items == null)
                {
                    string language = this.treeType == TreeTableType.Cities ? "zh-cn" : SiteContext.Current.Language;
                    items = treeTableDAL.GetModels(language);

                    AbsoluteTime time=new AbsoluteTime(DateTime.Now.AddMinutes(15));
                    Globals.GetCacheManage.Add(CacheKey, items, CacheItemPriority.Normal, null, time);
                }

                return items;
            }
        }

        private string CacheKey
        {
            get { return treeType + "-TreeView-" + SiteContext.Current.Language; }
        }

        private void ClearCache()
        {
            if(Globals.GetCacheManage.Contains(CacheKey))
                Globals.GetCacheManage.Remove(CacheKey);
        }

        private void UpdateCache(int categoryId)
        {
            if (categoryId <= 0)
                return;

            CategoryInfo info = treeTableDAL.GetModel(categoryId);
            if (info != null)
                UpdateCache(info);
        }
        private void UpdateCache(CategoryInfo categoryInfo)
        {
            if (categoryInfo == null)
                return;

            CategoryInfo label = GetCacheModel(categoryInfo.Id);
            if (label != null)
                Items.Remove(label);

            Items.Add(categoryInfo);
        }

        private void DeleteCache(int categoryId)
        {
            CategoryInfo label = GetCacheModel(categoryId);
            if(label!=null)
                Items.Remove(label);

        }

        private CategoryInfo GetCacheModel(int categoryId)
        {
            return  Items.SingleOrDefault(info => info.Id == categoryId);
        }
        #endregion
    }
}
